/*
 * Copyright (C) 2007,2008  Jonathan Hendler
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * 
 * The authors can be contacted at: 
 * @author Jonathan Hendler [jonathan DOT hendler AT google DOT com]
 * 
 * @license GPLv2
 */

/**
 * @todo - algorithm for DHT like awareness - 
 * http://portal.acm.org/citation.cfm?id=1272980.1272985&coll=GUIDE&dl=ACM&CFID=15151515&CFTOKEN=6184618
 * */
#include "nymrl.h"

/**
 * //TODO
 * */
inline int _nyml_get_ids_valid(NYMRL_ID id, char * rel){
	return TRUE;
}

#define NYMRL_SELF_URL_KEY "NYMRL_SELF_URL_KEY"

/**
 * Sends a request, via CURL, to the urls found from the query for nid, rel, and any or all
 * 
 * if NID or REL is null
 * 
 * gets the response, processes the header automatically to check
 * and returns the reply, without headers only. 
 * The reply will also be a string following the form of URLencoded data.
 * With content length. 
 * 
 *  // in fcgi
 *  // recieves a message - this is called manually ... maybe just a callback
 *  // recieves a message - forwards receives a message
 * 
 *    
 *  // dat is ALL dat in a string form
 *  // when this is starting a process maybe it is NULL
 * 
 * EITHER
 *  - create the header object from scratch
 *  - or get a header object from the request URL (using nymrl_recieve())
 * THEN pass it here.
 * 
 * */
inline nyml_header_struct * nyml_request(nyml_header_struct *  header){
		
    //NYMRL_ID nid, char * rel, enum nymrl_fwd fwd, char * dat, char * auth, char * act, int encrypt){
	int url_count;
	char * guid;
	int time;
	unsigned long chck;
	
	//nyml_header_struct * new_header;
	//nyml_header_struct * new_header_2;
	nyml_header_struct * current_header = header;
	
	int first_val = nymrl_first(header->fwd);
	int second_val = nymrl_second(header->fwd);
	int third_val = nymrl_third(header->fwd);
	
	//get URL list
	NYMRL_URL_LIST urls = NULL;
	
	//if dat is null and this is new creat new string and call it current dat
	
	if ((first_val != NONE) && (current_header->nid >0)){
		urls = _nymrl_get_url_switch(current_header->nid,current_header->rel,first_val,&url_count);
	}
	
	//if urls and forward before do sending
	// if there NONE and RESPOND BEFORE or AFTER isn't set, nothing will happen
	if (second_val == SEND_BEFORE){
	    if ((first_val != NONE) && (url_count >0)){
	    	//do forwarding of dat
	    	//?????????????
	    	// if URL count > 1???
	    	current_header = _nymrl_do_forward( urls,  url_count, current_header);
	    }
		
		if (third_val == RESPOND_BEFORE){
			//do callback with new_dat and don't set it to current_dat inse the response is already set
			_nymrl_do_callback(current_header->act,current_header->dat);
		} else if (third_val == RESPOND_AFTER) {
			//do callback with new_dat and set it to current_dat
			current_header->dat = _nymrl_do_callback(current_header->act,current_header->dat);
		}
	} else {
	//enum nymrl_fwd { NONE, ALL, ANY, ONE, SEND_BEFORE=10,SEND_AFTER=20, RESPOND_BEFORE=100, RESPOND_AFTER=200  };
	   if (third_val == RESPOND_BEFORE){
		    //?????????????
			//do response ?? of ok for current_dat
			//do callback with dat set it to new_dat, but don't update current dat
		   _nymrl_do_callback(current_header->act,current_header->dat);
		} else if (third_val == RESPOND_AFTER){
			//do callback with dat and set new_dat and update current_dat
		   current_header->dat = _nymrl_do_callback(current_header->act,current_header->dat);
		    
		}
	    
	    if ((first_val != NONE) && (url_count >0)){
	    	//do forwarding of new_dat and new rel
	    	//assume that response here is not needed, like sync updates to peers
	    	// and do not update current_dat
	    	_nymrl_do_forward( urls,  url_count, current_header);
	    }
	}
	
	
	//update time, checksum and messageids
	//generate guid
	guid = nymrl_get_guid();
	//generate time
	time = nymrl_get_time();
	//generate checksum for user data
	chck =  nymrl_message_hash(current_header->dat);
	
	
	//return a new object
	 
	return current_header;
}

/***
 *  get an object
 *  make it's string
 *  get a response string
 *  make an object
 **/
inline nyml_header_struct *  _nymrl_do_forward(NYMRL_URL_LIST urls, int url_count, nyml_header_struct *  header){
	char * post_string;
	char * response;
	char * url;
	NYMRL_URL_LIST urls_temp = urls;
	int i;
	nyml_header_struct *  new_header = NULL;
	
	//create post string
	post_string =  nymrl_get_string_from_header(header, FALSE);
	
	//get return string 
	if (url_count == 1){
		url = *urls_temp;
		response = nymrl_curl_post(url, post_string, NULL);
	} else {
		for (i=0;((i<url_count)&&(urls_temp));++i){
			//do curl
			//TODO ,, which response to choose
			// could choose the first, return it and handle the rest with threads
			// or using cURLs built in features.
			url = *urls_temp;
			if (strlen(url)>0){
				printf("\nsending to %s:\n%s",url,post_string);
				response = nymrl_curl_post(url, post_string, NULL);
				printf("\n got response\t%s\n", response);
			}
			++urls_temp;
		}
	}
	//deal withoutages
	//log time
	//make sure response has the desired content length malloced
	if (response && (strlen(response)>0) && nymrl_valid_string(response) ){
		//parse into new header, and free the memory from the response
		new_header =  nymrl_get_header_from_string(response, TRUE);
	}
	if (post_string) free(post_string);
	return new_header;
}

/**
 * warning calls dynamic functions
 * get an objects data string from encoded parametized list
 * do whatever
 * return new data string as encoded paramized list
 * 
 *  char * myfunction(char * act, char * data){
 * 		switch(act){
 * 		   //do stuff
 * 		}
 * 	}
 *  
 *  //set the function
 *  nymrl_callback_function = &myfunction;
 *  
 * good
 * http://www.newty.de/fpt/index.html
 * 
 * interesting http://neuralmom.media.mit.edu/neptune/funk.html
 * */
inline char * _nymrl_do_callback(char* act, char * dat){
	char * return_string = NULL;
	
	if (nymrl_callback_function == NULL){
		//log problem
		printf("\n ERROR nymrl_callback_function = NULL ");
		return NULL;
	} 
	
	if (nymrl_callback_function){
		return  (* nymrl_callback_function) (act,dat);
	}
	
	return NULL;
}

///TODO
// receive from fcgi the string,  the make  the struct, validate call the request function
 

/**
 * helper function
 * */
inline NYMRL_URL_LIST _nymrl_get_url_switch(NYMRL_ID nid,char * rel,int first_val,int * url_count){
	NYMRL_URL_LIST urls = NULL;
	
	switch (first_val){
		case ALL:
			urls = _nymrl_get_urls(0,  nid, rel,url_count);
			break;
		case ANY:
			urls = _nymrl_get_urls(1,  nid, rel,url_count);
			break;
		case ONE:
			//assume url is supplied
			break;
		case NONE:
		default:
			break;
	}
	
	return urls;
}

/**
 * helper application for a recieve only a standard POST string
 * use nyml_request() for initiating
 * */
inline char * nymrl_cgi_helper(char * post_content){
	nyml_header_struct * recieved;
	nyml_header_struct * processed;
	char * return_value;
	
	recieved = nymrl_get_header_from_string(post_content, TRUE);
	processed =  nyml_request(recieved);
	return_value = nymrl_get_string_from_header(processed, TRUE);
	
	return return_value;
}


/**
 * after receiving and processing, the header struct can be modified
 * and passed here to generate a string
 * each param is "key","value" and the = or & will be appended
 * */
inline char * nymrl_to_string( nyml_header_struct * header, ...){
	return "";
}

